﻿
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Analytics;

namespace Game
{
    public class ColliderMoveController : IMoveController
    {
        private Collider2D mCollider;
        private ContactFilter2D mFilter;

        private List<RaycastHit2D> mHitResults;
        private List<RaycastHit2D> mTangentHitResults;

        public Vector2 Forward
        {
            get;
            private set;
        }
        
        public ColliderMoveController(Collider2D collider, ContactFilter2D filter)
        {
            mCollider = collider;
            mFilter = filter;
            mHitResults = new List<RaycastHit2D>();
            mTangentHitResults = new List<RaycastHit2D>();
        }

        private Vector2 mLerpVector = Vector2.zero;
        private Vector2 mPushVector = Vector2.zero;
        public void Move(Vector2 direction, params object[] p)
        {
            //参数转换
            float speed = (float)p[0];
            float acceleration = (float)p[1];

            //移动方向
            direction = direction.normalized;
            Vector2 moveDir = speed * Time.deltaTime * direction;
            //更新缓动向量
            if (direction.x == 0) mLerpVector.x = 0;
            if (direction.y == 0) mLerpVector.y = 0;

            //缓动插值修正
            mLerpVector = Vector2.Lerp(mLerpVector, Vector2.one, acceleration);
            moveDir = mLerpVector * moveDir;

            //移动数据
            float moveDis = moveDir.magnitude;
            Vector2 finalDirection = direction;
            float finalDistance = moveDis;
            Vector2 updateDeltaPosition = Vector2.zero;
            //向移动方向发出射线
            mCollider.Cast(direction * direction.magnitude,mFilter,mHitResults,moveDis);
            foreach (var hit in mHitResults)
            {
                float distance = hit.distance;
                float projection = Vector2.Dot(hit.normal, direction);
                if (projection >= 0)
                {
                    distance = moveDis;
                } else
                {
                    Vector2 tangentDirection = new Vector2(hit.normal.y, -hit.normal.x);
                    float tangentDot = Vector2.Dot(tangentDirection, direction);
                    if (tangentDot < 0)
                    {
                        tangentDot = -tangentDot;
                        tangentDirection = -tangentDirection;
                    }
                    float tangentDistance = tangentDot * moveDis;
                    if (tangentDot != 0)
                    {
                        mCollider.Cast(tangentDirection, mFilter, mTangentHitResults,tangentDistance);
                        foreach (var tangentHit in mTangentHitResults)
                        {
                            if (Vector2.Dot(tangentHit.normal, tangentDirection) >= 0)
                                continue;

                            if (tangentHit.distance < tangentDistance)
                                tangentDistance = tangentHit.distance;
                        }

                        updateDeltaPosition += tangentDirection * tangentDistance;

                    }
                }
                if (distance < finalDistance)
                {
                    finalDistance = distance;
                }
            }
            updateDeltaPosition += finalDirection * finalDistance;

            Forward = updateDeltaPosition.normalized;
            
            //推动向量更新
            updateDeltaPosition += mPushVector;
            mPushVector = Vector2.Lerp(mPushVector, Vector2.zero, acceleration);

            mCollider.gameObject.transform.Translate(updateDeltaPosition);
        }
        
        public void Push(Vector2 direction,float force)
        {
            mPushVector = direction.normalized * force;
        }

        public void PushBack(float force)
        {
            Push(-Forward, force);
        }
    }
}